package org.springframework.boot.tests.hibernate52.mytest.beanFactorypostProcessor;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.boot.tests.hibernate52.mytest.annotation.Chris;
import org.springframework.context.annotation.*;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;

import java.io.IOException;
import java.util.Set;

/**
 * 自定义 BeanDefinitionRegistryPostProcessor 比 ConfigurationClassPostProcessor 类稍微逊一点 :)
 * <p>
 * 必须使用 full Configuration lite Component ComponentScan Import ImportResource Bean
 * <p>
 * 这些注解表明，{@link ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry}
 * 会定义处理这些注解修饰的类，并加入到BeanDefinition中
 * <p>
 * BeanDefinitionRegistryPostProcessor接口的本意只是修改或添加Bean定义，而不能去初始化实例
 */

@Component
public class MyBeanDefinitionRegistryPostProcessor
		implements BeanDefinitionRegistryPostProcessor, Ordered {

	protected final Log logger = LogFactory.getLog(MyBeanDefinitionRegistryPostProcessor.class);

	/**
	 * 参考 org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents(java.lang.String)
	 * <p>
	 * 扫描指定路径下的java类，是否有{@link Chris} 注解，然后注入bean定义
	 *
	 * @param registry
	 * @throws BeansException
	 */
	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
			throws BeansException {

		String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
				ClassUtils.convertClassNameToResourcePath("org.springframework.boot.tests.hibernate52.mytest.custombean") + '/' + "**/*.class";
		try {
			Resource[] resources = new PathMatchingResourcePatternResolver().getResources(packageSearchPath);
			for (Resource resource : resources) {
				logger.info("Scanning " + resource);
				if (resource.isReadable()) {
					MetadataReader metadataReader = new CachingMetadataReaderFactory().getMetadataReader(resource);
					AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
					if (annotationMetadata.hasAnnotation(Chris.class.getName())) {
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						sbd.setSource(resource);
						sbd.setResource(resource);
						registry.registerBeanDefinition(annotationMetadata.getClassName(), sbd);
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 此方法的执行比 postProcessBeanDefinitionRegistry 晚
	 *
	 * @param beanFactory
	 * @throws BeansException
	 */
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
			throws BeansException {

	}

	@Override
	public int getOrder() {
		return Ordered.LOWEST_PRECEDENCE;
	}

}
